package algorithms.evictpolicy;

public class EvictableCache<K, V> implements Cache<K, V> {

    private Cache<K, V> delegate;

    private EvictPolicy<K> evictPolicy;

    public EvictableCache(EvictPolicy<K> evictPolicy, Cache<K, V> delegate) {
        this.evictPolicy = evictPolicy;
        this.delegate = delegate;
    }

    public void put(K k, V v) {
        boolean put = evictPolicy.onPut(k, delegate.exists(k), delegate::remove);
        if (put) delegate.put(k, v);
    }

    public V get(K k) {
        evictPolicy.onGet(k, delegate.exists(k));
        return delegate.get(k);
    }

    @Override
    public boolean exists(K k) {
        if (delegate.exists(k)) {
            evictPolicy.onGet(k, true);
            return true;
        } else return false;
    }

    @Override
    public void remove(K k) {
        evictPolicy.onRemove(k, delegate.exists(k));
        delegate.remove(k);
    }

    public static void main(String[] args) {
        DefaultCache<String, Object> cache = new DefaultCache<>();
        EvictPolicy<String> lru = new LRUEvictPolicy<>(5);
        FIFOEvictPolicy<String> fifo = new FIFOEvictPolicy<>(5);
        EvictableCache<String, Object> evictableCache = new EvictableCache<>(lru, cache);
        evictableCache.put("Q", 100);
        evictableCache.put("B", 200);
        evictableCache.put("C", 300);
        evictableCache.put("D", 400);
        evictableCache.put("E", 500);
        evictableCache.put("F", 600);
        evictableCache.put("D", 800);
        System.out.println(evictableCache.get("Q"));
    }
}
